{-# LANGUAGE CPP, TemplateHaskell #-}
-----------------------------------------------------------------------------
--
-- Module      :  Main
-- Copyright   :
-- License     :  AllRightsReserved
--
-- Maintainer  :
-- Stability   :
-- Portability :
--
-- |
--
-----------------------------------------------------------------------------

module Main (
    main
) where

import Model
import Control.Monad (unless)
import Data.List
import System.Exit (exitFailure)
import Test.QuickCheck.All (quickCheckAll)

-- Simple function to create a hello message.
hello s = "Hello " ++ s

-- Tell QuickCheck that if you strip "Hello " from the start of
-- hello s you will be left with s (for any s).
prop_hello s = stripPrefix "Hello " (hello s) == Just s


isInteger s = case reads s :: [(Integer, String)] of
  [(_, "")] -> True
  _         -> False

isDouble s = case reads s :: [(Double, String)] of
  [(_, "")] -> True
  _         -> False

isNumeric :: String -> Bool
isNumeric s = isInteger s || isDouble s

-- Niestety nie udalo sie poprawnie napisac funkcji
-- pozwalajacej wczytac od uzytkownika listy stacji
-- z przyjazdami i odjazdami dla nowego kursu

{-
prepareVisits :: [Visit] -> [Station] -> [Course] -> [Visit]
prepareVisits v s k = do {
    --putStrLn "\nPodaj punkt trasy (stacje):";
    station <- getLine;
    if ((length station) > 0) then do {
        if (not (isNumeric station)) then do {
            if (elem station s) then do {
                putStrLn "Podaj czas przyjazdu";
                putStrLn "Podaj godzine:";
                arrivalH <- getLine;
                if ((isInteger arrivalH) && (arrivalH >= 0) && (arrivalH < 24)) then do {
                    putStrLn "\nPodaj minute:";
                    arrivalM <- getLine;
                    if ((isInteger arrivalM) && arrivalM >= 0 && arrivalM < 60) then do {
                        putStrLn "\nPodaj czas odjazdu";
                        putStrLn "Podaj godzine:";
                        departureH <- getLine;
                        if ((isInteger departureH) && departureH >= 0 && departureH < 24) then do {
                            putStrLn "\nPodaj minute:";
                            departureM <- getLine;
                            if ((isInteger departureM) && departureM >=0 && departureM < 60) then do {
                                return (prepareVisits (v ++ [Visit (Station station []) (Time (read arrivalH::Int) (read arrivalM::Int)) (Time (read departureH::Int) (read departureM::Int))]) s k);
                            }
                            else do {
                                putStrLn "Bledny format minut!";
                                return v;
                            }
                        }
                        else do {
                            putStrLn "Bledny format godziny!";
                            return v;
                        }
                    }
                    else do {
                        putStrLn "Bledny format minut!";
                        return v;
                    }
                }
                else do {
                    putStrLn "Bledny format godziny!";
                    return v;
                }
            }
            else do {
                putStrLn "Nie ma takiej stacji!";
                return v;
            }
        }
        else do {
            putStrLn "Niepoprawna forma nazwy stacji!";
            return v;
        }
    }
    else do {
        return v;
    }
}
-}

menu s k = do {
    putStrLn "\n-----------------------------------------------------------------";
    putStrLn "Stacje kolejowe: ";
    putStrLn "-------------------------------------------------------------------";
    putStrLn " s) dodaj stacje \t   d) usun stacje";
    putStrLn " x) wyswietl wszystkie stacje";
    putStrLn "-------------------------------------------------------------------";
    putStrLn "Kursy pociagow: ";
    putStrLn "-------------------------------------------------------------------";
    putStrLn " k) dodaj nowy kurs \t  l) usun kurs";
    putStrLn " m) wyswietl wszystkie kursy";
    putStrLn "-------------------------------------------------------------------";
    putStrLn "-------------------------------------------------------------------";
    putStrLn " w) wyszukaj polaczenie\t  r) wyswietl rozklad jazdy dla stacji";
    putStrLn "-------------------------------------------------------------------";
    putStrLn "-------------------------------------------------------------------";
    putStrLn " q) wyjscie z programu";
    putStrLn "-------------------------------------------------------------------\n";

    choice <- getLine;
    case choice of
        "s" -> do { -- dodanie stacji
                      putStrLn "Podaj nazwe stacji:";
                      name <- getLine;
                      if (not (isNumeric name)) then do {
                            if (notElem (Station name []) s) then do {
                                putStr "Dodano stacje: ";
                                putStrLn (show (Station name []));
                                menu (s ++ [Station name []]) k;
                            }
                            else do {
                                putStrLn "Stacja o podanej nazwie juz istnieje!";
                                menu s k;
                            }
                      }
                      else do {
                            putStrLn "Niepoprawna forma nazwy stacji!";
                            menu s k;
                      }
        }
        "d" -> do { -- usuwanie stacji
                      -- trzeba wpierw usunac wszyskie kursy, w ktorych jest ta stacja
                      putStrLn "Wszystkie stacje:\n";
                      putStrLn (concatMap presentStation s);
                      putStrLn "Wszystkie kursy:";
                      putStrLn (concatMap present k);
                      putStrLn "\nPodaj nazwe stacji, ktora chcesz usunac:";
                      name <- getLine;
                      if (notElem (Station name []) s) then do {
                            putStrLn "Nie ma takiej stacji!";
                            menu s k;
                      }
                      else if (canBeErased name k) then do {
                            putStrLn ("Usunieto stacje " ++ name ++ "\n");
                            menu (eraseStation name s) k;
                      }
                      else do {
                            putStrLn "Nie mozna usunac stacji! Istnieja kursy zwiazane z nia.";
                            putStrLn "Najpierw usun odpowiednie kursy, a potem stacje.";
                            menu s k;
                      }
        }
        "x" -> do { -- wyswietlenie stacji
                      putStrLn ("Lista stacji:\n"++(concatMap presentStation s));
                      menu s k;
        }
        "k" -> do { -- dodanie kursu
                      -- TODO
                      putStrLn "Prosze podac nazwe nowego kursu:";
                      name <- getLine;

                      -- Patrz - komentarz, linia 45
                      {-
                      if (not (isNumeric name)) then do {
                            -- TODO pointer
                            let pointer = 0
                            in
                            putStrLn "Koniec dodawania w przypadku podania pustej nazwy stacji.";
                            putStrLn "Prosze dodac co najmniej 2 punkty trasy!";
                            let visits = prepareVisits [] s k
                            in
                            if ((length visits) > 1) then do {
                                menu s (k ++ [Course name pointer visits [Mon, Tue, Wed,Thu,Fri,Sat,Sun]])
                            }
                            else do {
                                putStrLn "Podano za malo stacji do stworzenia kursu!";
                                menu s k;
                            }
                      }
                      else do {
                            putStrLn "Bledny format nazwy kursu!";
                            menu s k;
                      }
                      -}
                      menu s k;
        }
        "l" -> do { -- usuwanie kursu
                      putStrLn "Wszystkie kursy:\n";
                      putStrLn (concatMap present k);
                      putStrLn "\nPodaj nazwe kursu, ktory chcesz usunac:";
                      name <- getLine;
                      if (notElem (Course name 0 [] []) k) then do {
                            putStrLn "Nie ma takiego kursu!";
                            menu s k;
                      }
                      else do {
                            putStrLn ("Usuneito kurs " ++ name ++ "\n");
                            menu s (eraseCourse name k);
                      }
        }
        "m" -> do { -- wyswietlenie kursow
                      putStrLn (concatMap present k);
                      menu s k;
        }
        "w" -> do { -- wyszukiwanie polaczen
                      putStrLn ("Lista stacji:\n"++(concatMap presentStation s));
                      putStrLn "\nPodaj stacje startowa:";
                      from <- getLine;
                      if (not (isNumeric from)) then do {
                            putStrLn "\nPodaj stacje docelowa:";
                            to <- getLine;
                            if (not (isNumeric to)) then do {

                                putStrLn "\nPodaj dzien kursu:";
                                putStrLn "\nWpisz 'mon', 'tue', 'wed', 'thu', 'fri', 'sat' lub 'sun':";
                                dayStr <- getLine;

                                let day = case dayStr of "mon"  -> Mon
                                                         "tue"  -> Tue
                                                         "wed"  -> Wed
                                                         "thu"  -> Thu
                                                         "fri"  -> Fri
                                                         "sat"  -> Sat
                                                         "sun"  -> Sun
                                                         _      -> Invalid;
                                in
                                if (day/=Invalid)
                                  then do {
                                    putStrLn "\nPodaj maksymalna liczbe przesiadek";
                                    putStrLn "(jesli nie chcesz przesiadek podaj 0):";
                                    changes <- getLine;
                                    if ((isNumeric changes) && ((read changes ::Int) >= 0)) then do {
                                        putStrLn (presentConnections (findConnection (Station from []) (Station to []) s k day (read changes ::Int) []));
                                        menu s k;
                                    }
                                    else do {
                                        putStrLn "Niepoprawna maksymalna liczba przesiadek!";
                                        menu s k;
                                    }
                                }
                                else do {
                                    putStrLn "Nieporawna forma dnia kursowania!";
                                    menu s k;
                                }
                            }
                            else do {
                                putStrLn "Niepoprawna forma nazwy stacji!";
                                menu s k;
                            }
                      }
                      else do {
                            putStrLn "Niepoprawna forma nazwy stacji!";
                            menu s k;
                      }
        }
        "r" -> do { -- wyswietlenie rozkladu
                      putStrLn (presentSchedule (name (s!!0)) (generateSchedule (s!!0) s k));
                      menu s k;
        }
        "q" -> do { -- koniec programu
                      return 0;
        }
        "quit" -> do { -- jw.
                      return 0;
        }
        _  -> do {
                      putStrLn "Bledny wybor!";
                      putStrLn "Wybierz opcje ponownie.\n";
                      menu s k;
        }
}

-- Hello World
exeMain = do

    -- Inicjalizacja danych testowcych
    let stations = [Station "Bialystok" [],Station "Warszawa" [],Station "Krakow" [],Station "Gdansk" [],Station "Szczecin" []]
    let course = Course "Branicki" 3 [] [Mon, Tue, Wed,Thu,Fri]
    let maybeCourse = addVisit course (Visit (stations!!0) (Time 12 20) (Time 12 25))
    let course = case maybeCourse of Just c -> c
                                     Nothing -> Course "Anulowany" 1 [] []
    let maybeCourse = addVisit course (Visit (stations!!1) (Time 14 40) (Time 14 42))
    let course = case maybeCourse of Just c -> c
                                     Nothing -> Course "Anulowany" 1 [] []
    let stations2 = addCourse stations course
    let course2 = Course "Wodniaczek" 1 [] [Mon, Tue, Wed,Thu]
    let maybeCourse = addVisit course2 (Visit (stations!!2) (Time 13 30) (Time 13 35))
    let course2 = case maybeCourse of Just c -> c
                                      Nothing -> Course "Anulowany" 1 [] []
    let maybeCourse = addVisit course2 (Visit (stations!!3) (Time 17 21) (Time 17 22))
    let course2 = case maybeCourse of Just c -> c
                                      Nothing -> Course "Anulowany" 1 [] []
    let maybeCourse = addVisit course2 (Visit (stations!!0) (Time 20 21) (Time 20 28))
    let course2 = case maybeCourse of Just c -> c
                                      Nothing -> Course "Anulowany" 1 [] []
    let stations = addCourse stations2 course2

    putStrLn "------------------------------------------------";
    putStrLn "----------------------SPOP----------------------";
    putStrLn "--------------Rozklad jazdy PKP-----------------";
    putStrLn "--Autorzy: Arkadiusz Bazylewicz, Maciej Sikora--";
    putStrLn "------------------------------------------------";
    menu stations [course, course2];


-- Entry point for unit tests.
testMain = do
    allPass <- $quickCheckAll -- Run QuickCheck on all prop_ functions
    unless allPass exitFailure

-- This is a clunky, but portable, way to use the same Main module file
-- for both an application and for unit tests.
-- MAIN_FUNCTION is preprocessor macro set to exeMain or testMain.
-- That way we can use the same file for both an application and for tests.
#ifndef MAIN_FUNCTION
#define MAIN_FUNCTION exeMain
#endif
main = MAIN_FUNCTION

